﻿<?php

/**
 *		//核心类//
 *		//这是一份试验品，由大街编写（zhongmingzi@gmail.com）
 *		//本程序默认环境：Zend Optimizer Yes / 3.3.3
 *		//		Apache/2.0.63 (Win32) PHP/5.2.12
 *		//		MySQL 支持 Yes / client lib version 5.0.89
 *		//		GD library Yes / bundled (2.0.34 compatible)
 *		//		eAccelerator/Memcache/xcache Yes
 *		//		cURL support enabled
 *		//时间：2010 09 21 03:04:23//
 */
 
//常用变量

class core {

	var $db = null;
	var $mem = null;
	var $session = null;
	var $config = array();
	var $var = array();

	var $init_setting = true;
	var $init_user = true;
	var $init_session = true;
	var $init_misc = true;
	var $init_memory = true;

	var $initated = false;

	var $superglobal = array(
		'GLOBALS' => 1,
		'_GET' => 1,
		'_POST' => 1,
		'_REQUEST' => 1,
		'_COOKIE' => 1,
		'_SERVER' => 1,
		'_ENV' => 1,
		'_FILES' => 1,
	);

	function &instance() {
		static $object;
		if(empty($object)) {
			$object = new core();
		}
		return $object;
	}

	function core() {
		$this->_init_env();
		$this->_init_config();
		$this->_init_input();
		$this->_init_output();
	}

	function init() {
		if(!$this->initated) {
			$this->_init_db();
			//$this->_init_memory();
			$this->_init_user();
			$this->_init_session();
			//$this->_init_setting();
			//$this->_init_cron();
			$this->_init_misc();
		}
		$this->initated = true;
	}

	function _init_env() {

		error_reporting(E_PARSE OR E_ERROR);
		if(phpversion() < '5.3.0') {
			set_magic_quotes_runtime(0);
		}

		//最后不带/
		define('ROOT', substr(dirname(__FILE__), 0, -15));
		define('MAGIC', function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc());
		define('ICONV', function_exists('iconv'));
		define('MB', function_exists('mb_convert_encoding'));
		define('OB', function_exists('ob_gzhandler'));
		define('IN', true);
		define('IP', $this->ip());
		define('CACHE_DATA', ROOT.'./data/cache/');
		define('HOST', 'http://'.$_SERVER['HTTP_HOST']);
		if(!defined('CORE_FUNCTION') && !@include(ROOT.'./framework/function/function_core.php')) {
			exit('function_core.php is missing');
		}

		define('TIMESTAMP', time());
		define('TIME', microtime(true));
		$this->timezone_set();
		
		//@
		if(function_exists('ini_get')) {
			$memorylimit = @ini_get('memory_limit');
			if($memorylimit && return_bytes($memorylimit) < 33554432 && function_exists('ini_set')) {
				ini_set('memory_limit', '128m');
			}
		}

		define('ROBOT', $this->checkrobot());

		foreach ($GLOBALS as $key => $value) {
			if (!isset($this->superglobal[$key])) {
				$GLOBALS[$key] = null; 
				unset($GLOBALS[$key]);
			}
		}

		global $_G;
		$_G = array(
			'uid' => 0,
			'username' => '',
			'adminid' => 0,
			'groupid' => 0,
			'city' => '',
			'cint' => "Source",
			'sid' => '',
			'formhash' => '',
			'timestamp' => TIMESTAMP,
			'starttime' => TIME,
			'ip' => $this->ip(),
			'referer' => '',
			'charset' => '',
			'gzipcompress' => '',
			'authkey' => '',
			'timenow' => array(),

			'PHP_SELF' => '',
			'url' => '',
			'siteroot' => '',

			'config' => array(),
			'setting' => array(),
			'member' => array(),
			'group' => array(),
			'cookie' => array(),
			'style' => array(),
			'cache' => array(),
			'session' => array(),

			'block' => array(),
			'article' => array(),

			'action' => array(
				'action' => APPTYPEID,
			)
		);
		$_G['PHP_SELF'] = htmlspecialchars($_SERVER['SCRIPT_NAME'] ? $_SERVER['SCRIPT_NAME'] : $_SERVER['PHP_SELF']);
		$_G['basescript'] = CURSCRIPT;
		$_G['basefilename'] = basename($_G['PHP_SELF']);
		$_G['url'] = htmlspecialchars('http://'.$_SERVER['HTTP_HOST'].preg_replace("/\/+(api)?\/*$/i", '', substr($_G['PHP_SELF'], 0, strrpos($_G['PHP_SELF'], '/'))));
		$_G['fullurl'] = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
		$_G['securl'] = substr_replace($_G['fullurl'], '', 0, strlen($_G['url']));
		define('URL', $_G['url']);//.substr(ROOT, strlen($_SERVER['DOCUMENT_ROOT'])));
		define('SECURL', $_G['securl']);
		define('REFERER', $_SERVER['REQUEST_URI']);
		$_G['siteroot'] = substr($_G['PHP_SELF'], 0, -strlen($_G['basefilename']));
		if(defined('SUB_DIR')) {
			$_G['siteurl'] = str_replace(SUB_DIR, '/', $_G['siteurl']);
			$_G['siteroot'] = str_replace(SUB_DIR, '/', $_G['siteroot']);
		}
		$this->var = & $_G;

	}
	
	function _init_config() {

		$_config = array();
		@include ROOT.'./config/config_global.php';
		if(empty($_config)) {
			system_error('配置文件丢失！');
		}

		//@
		if(empty($_config['security']['authkey'])) {
			$_config['security']['authkey'] = md5($_config['cookie']['cookiepre'].$_config['db'][1]['dbname']);
		}

		if(empty($_config['debug'])) {
			define('DEBUG', false);
		} elseif($_config['debug'] === 1 || $_config['debug'] === 2) {
			define('DEBUG', true);
			if($_config['debug'] == 2) {
				error_reporting(E_ALL);
			}
		} else {
			define('DEBUG', false);
		}

		define('STATICURL', !empty($_config['output']['staticurl']) ? $_config['output']['staticurl'] : 'static/');
		$this->var['staticurl'] = STATICURL;

		$this->config = & $_config;
		$this->var['config'] = & $_config;

		if(substr($_config['cookie']['cookiepath'], 0, 1) != '/') {
			$this->var['config']['cookie']['cookiepath'] = '/'.$this->var['config']['cookie']['cookiepath'];
		}
		$this->var['config']['cookie']['cookiepre'] = $this->var['config']['cookie']['cookiepre'].substr(md5($this->var['config']['cookie']['cookiepath'].'|'.$this->var['config']['cookie']['cookiedomain']), 0, 3).'_';
		$this->var['authkey'] = md5($_config['security']['authkey'].$_SERVER['HTTP_USER_AGENT']);

	}

	function _init_input() {

		if (isset($_GET['GLOBALS']) ||isset($_POST['GLOBALS']) ||  isset($_COOKIE['GLOBALS']) || isset($_FILES['GLOBALS'])) {
			system_error('脏数据！');
		}

		//@
		if(!MAGIC) {
			$_GET = daddslashes($_GET);
			$_POST = daddslashes($_POST);
			$_COOKIE = daddslashes($_COOKIE);
			$_FILES = daddslashes($_FILES);
		}

		$prelength = strlen($this->config['cookie']['cookiepre']);
		foreach($_COOKIE as $key => $val) {
			if(substr($key, 0, $prelength) == $this->config['cookie']['cookiepre']) {
				$this->var['cookie'][substr($key, $prelength)] = $val;
			}
		}
		
		//这里对page的优先级做一个调整，让post的大于get的
		if(isset($_POST['page']) && isset($_GET['page'])) unset($_GET['page']);
		foreach(array_merge($_POST, $_GET) as $k => $v) {
			$this->var['gp_'.$k] = $v;
		}
		$this->var['mod'] = empty($this->var['gp_mod']) ? '' : htmlspecialchars($this->var['gp_mod']);
		$this->var['fun'] = empty($this->var['gp_fun']) ? '' : htmlspecialchars($this->var['gp_fun']);
		$this->var['inajax'] = empty($this->var['gp_inajax']) ? 0 : (empty($this->var['config']['output']['ajaxvalidate']) ? 1 : ($_SERVER['REQUEST_METHOD'] == 'GET' && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest' || $_SERVER['REQUEST_METHOD'] == 'POST' ? 1 : 0));
		$this->var['page'] = empty($this->var['gp_page']) ? 1 : max(1, intval($this->var['gp_page']));
		$this->var['sid'] = $this->var['cookie']['sid'] = isset($this->var['cookie']['sid']) ? htmlspecialchars($this->var['cookie']['sid']) : '';
	}

	function _init_output() {

		if($this->config['security']['urlxssdefend'] && $_SERVER['REQUEST_METHOD'] == 'GET' && !empty($_SERVER['REQUEST_URI'])) {
			$temp = urldecode($_SERVER['REQUEST_URI']);
			if(strpos($temp, '<') !== false || strpos($temp, '"') !== false) {
				system_error('脏数据！');
			}
		}

		$allowgzip = $this->config['output']['gzip'] && empty($this->var['inajax']) && $this->var['mod'] != 'attachment' && OB;
		setglobal('gzipcompress', $allowgzip);
		//ob_start($allowgzip ? 'ob_gzhandler' : null);

		setglobal('charset', $this->config['output']['charset']);
		define('CHARSET', $this->config['output']['charset']);
		if($this->config['output']['forceheader']) {
			@header('Content-Type: text/html; charset='.CHARSET);
		}

	}

	function _init_db() {
		$this->db = & DB::object();
		$this->db->set_config($this->config['db']);
		$this->db->connect();
	}
	
	function _init_memory() {
		$this->mem = new memory();
		if($this->init_memory) {
			$this->mem->init($this->config['memory']);
		}
		$this->var['memory'] = $this->mem->type;
	}

	function _init_user() {
		if($this->init_user) {
			include_once libfile('class/member');
			if($auth = getglobal('auth', 'cookie')) {
				$auth = daddslashes(explode("\t", authcode($auth, 'DECODE')));
				list($pw, $uid) = empty($auth) || count($auth) < 2 ? array('', '') : $auth;

				if($uid) {
					$user = getuserbyuid($uid);
				}
				
				if(!empty($user) && $user['password'] == $pw) {
					include_once libfile('class/pm');
					$this->var['member'] = $user;
					//在这里对上次登录时间做一个备份。
					$this->var['member']['prlastvisit'] = $this->var['member']['lastvisit'];
				} else {
					$user = array();
					$this->_init_guest();
				}
			} else {
				$user = array();
				$this->_init_guest();
			}

		} else {
			$this->_init_guest();
		}
		//这里如果是首次登陆，则给cookie的lastvisit赋值，这个值一般是不变的。这里暂时不考虑游客。
		if(empty($this->var['cookie']['lastvisit']) && $this->var['member']['lastvisit'] ) {
			dsetcookie('lastvisit', $this->var['member']['lastvisit'], 86400 * 30);
		} elseif($this->var['cookie']['lastvisit']) {
			$this->var['member']['lastvisit'] = $this->var['cookie']['lastvisit'];
		}
		setglobal('uid', getglobal('uid', 'member'));
		setglobal('username', getglobal('username', 'member'));
		setglobal('adminid', getglobal('adminid', 'member'));
		setglobal('groupid', getglobal('groupid', 'member'));
		setglobal('city', getglobal('city', 'member'));
	}

	function _init_guest() {
		$guestname = explode('.', IP);
		$guestname[3] = "×";
		$guestname = implode('.', $guestname);
		setglobal('member', array( 'uid' => 0, 'username' => $guestname, 'city' => '','adminid' => 0, 'groupid' => 0, 'credits' => 0, 'timeoffset' => 9999));
		setglobal('uid', getglobal('uid', 'member'));
		setglobal('username', getglobal('username', 'member'));
		setglobal('adminid', getglobal('adminid', 'member'));
		setglobal('groupid', getglobal('groupid', 'member'));
		setglobal('city', getglobal('city', 'member'));
	}

	function _init_session() {

		$this->session = new session();

		if($this->init_session) {
			$this->session->init($this->var['cookie']['sid'], $this->var['ip'], $this->var['uid']);
			$this->var['sid'] = $this->session->sid;
			$this->var['session'] = $this->session->var;
			//当IP地址有更换的时候，则会自动生成新的sid值。一般在掉线或者更换主机后出现。
			if($this->var['sid'] != $this->var['cookie']['sid']) {
				dsetcookie('sid', $this->var['sid'], 86400);
			}
			//如果重新建立sid后，则会对用户进行组别判断
			if($this->session->isnew) {
				if(ipbanned($this->var['ip'])) {
					$this->session->set('groupid', 9);//9设置为IP禁止访问组别
				}
			}

			if($this->session->get('groupid') == 9) {
				$this->var['member']['groupid'] = 9;
				showmessage('user_banned');
			}
			//在页面刚载入初始化session部分的时候，给lastactivity赋值
			//如果用户一直保持着session状态，则这里判断上次活动时间10分钟是否已过，如果已过则重新给lastactivity赋值
			if($this->var['uid'] && ($this->session->isnew || ($this->session->get('lastactivity') + 600) < TIMESTAMP)) {

				$this->session->set('lastactivity', TIMESTAMP);
				//如果是更换了IP的情况或者重新登陆，则在这里重新生成统计信息，每次重新登陆都会重新统计
				//和updatesession里更新这信息的区别，这里主要是针对重新生成sessionDB信息后，判断为重新登陆
				//对lastvisit登陆时间赋值，而那里则是针对长时间无操作，重新生成统计信息
				if($this->session->isnew) {
					dsetcookie('lastvisit', $this->var['member']['prlastvisit'], 86400 * 30);
					$this->var['member']['lastvisit'] = $this->var['member']['prlastvisit'];
					
					$ipconv = ipconvert($this->var['ip']);
					$city = $ipconv['country_code'] == 'CN' ? $ipconv['cncity'] : $ipconv['city'];
					$code = $ipconv['country_code'];
					DB::update('u_members', array('lastip' => $this->var['ip'], 'lastvisit' => TIMESTAMP), "uid='".$this->var['uid']."'");
					DB::update('u_members_pro', array('city' => $city, 'code' => $code),"uid='".$this->var['uid']."'");
				}
			}

		}
	}

	function _init_misc() {

		if(!$this->init_misc) {
			return false;
		}

		if($this->init_setting && $this->init_user) {
			if(!isset($this->var['member']['timeoffset']) || $this->var['member']['timeoffset'] == 9999 || $this->var['member']['timeoffset'] === '') {
				$this->var['member']['timeoffset'] = $this->var['setting']['timeoffset'];
			}
		}

		$timeoffset = $this->init_setting ? $this->var['member']['timeoffset'] : $this->var['setting']['timeoffset'];
		$this->var['timenow'] = array(
			'time' => dgmdate(TIMESTAMP),
			'offset' => $timeoffset >= 0 ? ($timeoffset == 0 ? '' : '+'.$timeoffset) : $timeoffset
		);
		$this->timezone_set($timeoffset);

		$this->var['formhash'] = formhash();
		define('FORMHASH', $this->var['formhash']);

		if($this->var['setting']['ipaccess'] && !ipaccess($this->var['ip'], $this->var['setting']['ipaccess'])) {
			sysmessage('user_banned', null);
		}

		if($this->var['setting']['bbclosed']) {
		}

		if($this->var['setting']['nocacheheaders']) {
			@header("Expires: -1");
			@header("Cache-Control: no-store, private, post-check=0, pre-check=0, max-age=0", FALSE);
			@header("Pragma: no-cache");
		}

		$lastact = TIMESTAMP."\t".htmlspecialchars(basename($this->var['PHP_SELF']))."\t".htmlspecialchars($this->var['mod']);
		dsetcookie('lastact', $lastact, 86400);
		setglobal('currenturl_encode', base64_encode('http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']));

		$this->var['seokeywords'] = !empty($this->var['setting']['seokeywords'][CURSCRIPT]) ? $this->var['setting']['seokeywords'][CURSCRIPT] : '';
		$this->var['seodescription'] = !empty($this->var['setting']['seodescription'][CURSCRIPT]) ? $this->var['setting']['seodescription'][CURSCRIPT] : '';

	}

	function _init_style() {
		$styleid = !empty($this->var['cookie']['styleid']) ? $this->var['cookie']['styleid'] : 0;
		if($styleid && $styleid != $this->var['setting']['styleid']) {
			loadcache('style_'.$styleid);
			if($this->var['cache']['style_'.$styleid]) {
				$this->var['style'] = $this->var['cache']['style_'.$styleid];
			}
			$this->var['group']['allowdiy'] = 0;
		}

		if(is_array($this->var['style'])) {
			foreach ($this->var['style'] as $key => $val) {
				$key = strtoupper($key);
				if(!defined($key) && !is_array($val)) {
					define($key, $val);
				}
			}
		}
	}

	function timezone_set($timeoffset = 8) {//这里设置默认时区为东八区
		if(function_exists('date_default_timezone_set')) {
			@date_default_timezone_set('Etc/GMT'.($timeoffset > 0 ? '-' : '+').(abs($timeoffset)));
		}
	}
	
	function checkrobot($useragent = '') {
		static $kw_spiders = 'Bot|Crawl|Spider|slurp|sohu-search|lycos|robozilla';
		static $kw_browsers = 'MSIE|Netscape|Opera|Konqueror|Mozilla';

		$useragent = empty($useragent) ? $_SERVER['HTTP_USER_AGENT'] : $useragent;

		if(!strexists($useragent, 'http://') && preg_match("/($kw_browsers)/i", $useragent)) {
			return false;
		} elseif(preg_match("/($kw_spiders)/i", $useragent)) {
			return true;
		} else {
			return false;
		}
	}
	
	function reject_robot() {
		if(ROBOT) {
			exit(header("HTTP/1.1 403 Forbidden"));
		}
	}

	function ip() {
		$clientip = '';
		if(getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) {
			$clientip = getenv('HTTP_CLIENT_IP');
		} elseif(getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) {
			$clientip = getenv('HTTP_X_FORWARDED_FOR');
		} elseif(getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) {
			$clientip = getenv('REMOTE_ADDR');
		} elseif(isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
			$clientip = $_SERVER['REMOTE_ADDR'];
		}

		preg_match("/[\d\.]{7,15}/", $clientip, $clientipmatches);
		$clientip = $clientipmatches[0] ? $clientipmatches[0] : 'Unknown';
		return $clientip;
	}
}

class db_mysql
{
	var $tablepre;
	var $querynum = 0;
	var $slaveid = 0;
	var $curlink;
	var $rs;
	var $link = array();
	var $config = array();
	var $sqldebug = array();
	var $map = array();

	function db_mysql($config = array()) {
		if(!empty($config)) {
			$this->set_config($config);
		}
	}

	function set_config($config) {
		$this->config = &$config;
		$this->tablepre = $config['1']['tablepre'];
	}

	function connect($serverid = 1) {
		$this->link[$serverid] = $this->_dbconnect(
			$this->config[$serverid]['dbhost'],
			$this->config[$serverid]['dbuser'],
			$this->config[$serverid]['dbpw'],
			$this->config[$serverid]['dbcharset'],
			$this->config[$serverid]['dbname']
		);
		$this->curlink = $this->link[$serverid];
	}

	function _dbconnect($host, $user, $pw, $charset, $name) {
		$link = null;
		$dsn =  "mysql:host=$host;dbname=$name";
		if(!$link = new PDO($dsn, $user, $pw, array( 
			PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true, 
		))) {
			$this->halt('没有连接！请确认是否有PDO组件！');
		} else {
			$this->curlink = $link;
			$this->curlink->exec("SET NAMES $charset");
		}
		return $link;
	}

	function table_name($tablename) {
		if(!empty($this->map) && !empty($this->map[$tablename])) {
			$id = $this->map[$tablename];
			if(!$this->link[$id]) {
				$this->connect($id);
			}
			$this->curlink = $this->link[$id];
		} else {
			$this->curlink = $this->link[1];
		}
		return $this->tablepre.$tablename;
	}
	
	function fetch() {
		if(!$this->rs) return false;
		else return $this->rs->fetch(PDO::FETCH_ASSOC);
	}

	function fetch_all($sql) {
		if(!$this->query($sql)) return false;
		else return $this->rs->fetchAll(PDO::FETCH_ASSOC);
	}

	function fetch_first($sql) {
		if(!$this->query($sql)) return false;
		else return $this->rs->fetch(PDO::FETCH_ASSOC);
	}

	function result_first($sql) {
		if(!$this->query($sql)) return false;
		else return $this->rs->fetchColumn();
	}

	/**
	 * 处理一条SQL语句，并返回一个“PDOStatement”
	 * @return PDOstatement
	 */
	function query($sql, $type = '') {
		if(!($this->rs = $this->curlink->query($sql))) {
			if($type != 'SILENT' && substr($type, 5) != 'SILENT') {
				$this->halt('查询错误！', $sql);
			}
		}
		$this->querynum++;
		return $this->rs;
	}
	
	/**
	 * 处理一条SQL语句，并返回所影响的条目数
	 * @return int
	 */
	function exec($sql, $type = '') {
		$rows = $this->curlink->exec($sql);
		if($rows === false) {
			if($type != 'SILENT' && substr($type, 5) != 'SILENT') {
				$this->halt('查询错误！', $sql);
			}
		}
		$this->querynum++;
		return $rows;
	}

	/**
	 * 只针对insert，update，delete的统计，只能针对query的操作
	 * @return affected rows
	 */
	function affected_rows() {
		if(!$this->rs) return false;
		return $this->rs->rowCount();
	}

	function error() {
		if(!$this->rs) {
			return $this->curlink->errorInfo();
		} 
		return $this->rs->errorInfo();
	}

	function errno() {
		if(!$this->rs) {
			return $this->curlink->errorCode();
		} 
		return $this->rs->errorCode();
	}

	function result($sql, $row = 0) {
		if(!$this->query($sql)) return false;
		else return $this->rs->fetchColumn($row);
	}

	function insert_id() {
		return $this->curlink->lastInsertId();
	}
	
	function free_result($query) {
		 $this->rs = null;
	}

	function halt($message = '', $sql = '') {
		require_once libfile('class/error');
		error::db_error($message, $sql);
	}
}

class DB {

	function t($table) {
		return DB::_execute('table_name', $table);
	}
	
	function table($table) {
		return DB::_execute('table_name', $table);
	}

	function delete($table, $condition, $limit = 0) {
		if(empty($condition)) {
			$where = '1';
		} elseif(is_array($condition)) {
			$where = DB::implode_field_value($condition, ' AND ');
		} else {
			$where = $condition;
		}
		$sql = "DELETE FROM ".DB::table($table)." WHERE $where ".($limit ? "LIMIT $limit" : '');
		return DB::exec($sql);
	}

	function insert($table, $data, $return_insert_id = false, $replace = false, $silent = false) {

		$sql = DB::implode_field_value($data);

		$cmd = $replace ? 'REPLACE INTO' : 'INSERT INTO';

		$table = DB::table($table);
		$silent = $silent ? 'SILENT' : '';

		$return = DB::exec("$cmd $table SET $sql", $silent);

		return $return_insert_id ? DB::insert_id() : $return;

	}

	function update($table, $data, $condition, $low_priority = false) {
		$sql = DB::implode_field_value($data);
		$cmd = "UPDATE ".($low_priority ? 'LOW_PRIORITY' : '');
		$table = DB::table($table);
		$where = '';
		if(empty($condition)) {
			$where = '1';
		} elseif(is_array($condition)) {
			$where = DB::implode_field_value($condition, ' AND ');
		} else {
			$where = $condition;
		}
		$res = DB::exec("$cmd $table SET $sql WHERE $where");
		return $res;
	}

	function implode_field_value($array, $glue = ',') {
		$sql = $comma = '';
		foreach ($array as $k => $v) {
			$sql .= $comma."`$k`='$v'";
			$comma = $glue;
		}
		return $sql;
	}
	
	function operation($dbname, $field, $condition, $type = '+', $num = 1) {
		if($type != '+') $type = '-';
		return DB::exec("UPDATE ".DB::t($dbname)." SET $field = $field $type $num WHERE $condition");
	}

	function insert_id() {
		return DB::_execute('insert_id');
	}

	function fetch() {
		return DB::_execute('fetch');
	}
	
	function fetch_all($sql) {
		DB::checkquery($sql);
		return DB::_execute('fetch_all', $sql);
	}

	function fetch_first($sql) {
		DB::checkquery($sql);
		return DB::_execute('fetch_first', $sql);
	}

	function result($sql, $row = 0) {
		DB::checkquery($sql);
		return DB::_execute('result', $sql, $row);
	}

	function result_first($sql) {
		DB::checkquery($sql);
		return DB::_execute('result_first', $sql);
	}

	function query($sql) {
		DB::checkquery($sql);
		return DB::_execute('query', $sql);
	}
	
	function exec($sql) {
		DB::checkquery($sql);
		return DB::_execute('exec', $sql);
	}

	//不用
	function num_rows() {
	}

	function affected_rows() {
		return DB::_execute('affected_rows');
	}

	function free_result($query) {
		return DB::_execute('free_result', $query);
	}

	function error() {
		return DB::_execute('error');
	}

	function errno() {
		return DB::_execute('errno');
	}

	function _execute($cmd , $arg1 = '', $arg2 = '') {
		static $db;
		if(empty($db)) $db = & DB::object();
		$res = $db->$cmd($arg1, $arg2);
		return $res;
	}

	function &object() {
		static $db;
		if(empty($db)) $db = new db_mysql();
		return $db;
	}

	function checkquery($sql) {
		static $status = null, $checkcmd = array('SELECT', 'UPDATE', 'INSERT', 'REPLACE', 'DELETE');
		if($status === null) $status = getglobal('config/security/querysafe/status');
		if($status) {
			$cmd = trim(strtoupper(substr($sql, 0, strpos($sql, ' '))));
			if(in_array($cmd, $checkcmd)) {
				$test = DB::_do_query_safe($sql);
				if($test < 1) DB::_execute('halt', 'security_error', $sql." ErrorCode:".$test);
			}
		}
		return true;
	}

	function _do_query_safe($sql) {
		static $_CONFIG = null;
		if($_CONFIG === null) {
			$_CONFIG = getglobal('config/security/querysafe');
		}

		$sql = str_replace(array('\\\\', '\\\'', '\\"', '\'\''), '', $sql);
		$mark = $clean = '';
		if(strpos($sql, '/') === false && strpos($sql, '#') === false && strpos($sql, '-- ') === false) {
			$clean = preg_replace("/'(.+?)'/s", '', $sql);
		} else {
			$len = strlen($sql);
			$mark = $clean = '';
			for ($i = 0; $i <$len; $i++) {
				$str = $sql[$i];
				switch ($str) {
					case '\'':
						if(!$mark) {
							$mark = '\'';
							$clean .= $str;
						} elseif ($mark == '\'') {
							$mark = '';
						}
						break;
					case '/':
						if(empty($mark) && $sql[$i+1] == '*') {
							$mark = '/*';
							$clean .= $mark;
							$i++;
						} elseif($mark == '/*' && $sql[$i -1] == '*') {
							$mark = '';
							$clean .= '*';
						}
						break;
					case '#':
						if(empty($mark)) {
							$mark = $str;
							$clean .= $str;
						}
						break;
					case "\n":
						if($mark == '#' || $mark == '--') {
							$mark = '';
						}
						break;
					case '-':
						if(empty($mark)&& substr($sql, $i, 3) == '-- ') {
							$mark = '-- ';
							$clean .= $mark;
						}
						break;

					default:

						break;
				}
				$clean .= $mark ? '' : $str;
			}
		}

		$clean = preg_replace("/[^a-z0-9_\-\(\)#\*\/\"]+/is", "", strtolower($clean));

		if($_CONFIG['afullnote']) {
			$clean = str_replace('/**/','',$clean);
		}

		if(is_array($_CONFIG['dfunction'])) {
			foreach($_CONFIG['dfunction'] as $fun) {
				if(strpos($clean, $fun.'(') !== false) return '-1';
			}
		}

		if(is_array($_CONFIG['daction'])) {
			foreach($_CONFIG['daction'] as $action) {
				if(strpos($clean,$action) !== false) return '-3';
			}
		}

		if($_CONFIG['dlikehex'] && strpos($clean, 'like0x')) {
			return '-2';
		}

		if(is_array($_CONFIG['dnote'])) {
			foreach($_CONFIG['dnote'] as $note) {
				if(strpos($clean,$note) !== false) return '-4';
			}
		}

		return 1;

	}

}

class session {

	var $sid = null;
	var $var;
	var $isnew = false;
	var $newguest = array('sid' => 0, 'ip1' => 0, 'ip2' => 0, 'ip3' => 0, 'ip4' => 0,
	'uid' => 0, 'username' => '', 'groupid' => 0, 'invisible' => 0, 'action' => 0,
	'lastactivity' => 0, 'lastolupdate' => 0);

	var $old =  array('sid' =>  '', 'ip' =>  '', 'uid' =>  0);

	function session($sid = '', $ip = '', $uid = 0) {
		$this->old = array('sid' =>  $sid, 'ip' =>  $ip, 'uid' =>  $uid);
		$this->var = $this->newguest;
		if(!empty($ip)) {
			$this->init($sid, $ip, $uid);
		}
	}

	function set($key, $value) {
		if(isset($this->newguest[$key])) {
			$this->var[$key] = $value;
		} elseif ($key == 'ip') {
			$ips = explode('.', $value);
			$this->set('ip1', $ips[0]);
			$this->set('ip2', $ips[1]);
			$this->set('ip3', $ips[2]);
			$this->set('ip4', $ips[3]);
		}
	}

	function get($key) {
		if(isset($this->newguest[$key])) {
			return $this->var[$key];
		} elseif ($key == 'ip') {
			return $this->get('ip1').'.'.$this->get('ip2').'.'.$this->get('ip3').'.'.$this->get('ip4');
		}
	}

	function init($sid, $ip, $uid) {
		$this->old = array('sid' =>  $sid, 'ip' =>  $ip, 'uid' =>  $uid);
		$session = array();
		if($sid) {
			$session = DB::fetch_first("SELECT * FROM ".DB::table('c_session').
				" WHERE sid='$sid' AND CONCAT_WS('.', ip1,ip2,ip3,ip4)='$ip'");
		}

		if(empty($session) || $session['uid'] != $uid) {
			$session = $this->create($ip, $uid);
		}

		$this->var = $session;
		$this->sid = $session['sid'];
	}

	function create($ip, $uid) {

		$this->isnew = true;
		$this->var = $this->newguest;
		$this->set('sid', random(6));
		$this->set('uid', $uid);
		$this->set('ip', $ip);
		$this->set('lastactivity', time());
		$this->sid = $this->var['sid'];

		return $this->var;
	}

	function delete() {

		global $_G;
		$onlinehold = $_G['setting']['onlinehold'];
		$guestspan = 60;

		$onlinehold = time() - $onlinehold;
		$guestspan = time() - $guestspan;

		$condition = " sid='{$this->sid}' ";
		$condition .= " OR lastactivity<$onlinehold ";
		$condition .= " OR (uid='0' AND ip1='{$this->var['ip1']}' AND ip2='{$this->var['ip2']}' AND ip3='{$this->var['ip3']}' AND ip4='{$this->var['ip4']}' AND lastactivity>$guestspan) ";
		$condition .= $this->var['uid'] ? " OR (uid='{$this->var['uid']}') " : '';
		DB::delete('c_session', $condition);
	}

	function update() {
		if($this->sid !== null) {

			$data = daddslashes($this->var);
			if($this->isnew) {
				$this->delete();
				DB::insert('c_session', $data, false, false, true);
			} else {
				DB::update('c_session', $data, "sid='$data[sid]'");
			}
			dsetcookie('sid', $this->sid, 86400);
		}
	}

	function onlinecount($type = 0) {
		$condition = $type == 1 ? ' WHERE uid>0 ' : ($type == 2 ? ' WHERE invisible=1 ' : '');
		return DB::result_first("SELECT count(*) FROM ".DB::table('c_session').$condition);
	}

}


?>
